简析 Python 的 NotImplemented
关注他
13 人赞同了该文章
简评:本文讨论 Python 的
NotImplemented它是什么,它意味着什么,什么时候应该使用。
是什么
>>> type(NotImplemented)
<type 'NotImplementedType'>
NotImplemented是 Python 内置命名空间中的六个常量之一。其他还有 False, True, None, Ellipsis 和 __debug__。类似于 Ellipsis,NotImplemented可以重新赋值。 赋值给它,即使作为属性名称,也不会引发SyntaxError异常,所以它不是真正的“真实(real/true)”的常量。当然,我们永远都不应该重新赋值它。 但是,为了完整:
>>> None = 'hello'
...
SyntaxError: can't assign to keyword
>>> NotImplemented
NotImplemented
>>> NotImplemented = 'do not'
>>> NotImplemented
'do not'
意味着什么,什么时候用
NotImplemented是 python 特殊二元方法(例如__eq__(), __lt__(), __add__(), __rsub__())返回的特殊值,表示该操作没有针对其他类型实现。而且,它转换成 bool 类型表示 true:
>>> bool(NotImplemented)
True
可能会有这样的疑问「应该在操作没有实现时抛出NotImpementedError异常」,通过一些例子,我们将看到为什么在实现二元特殊方法时不应该这样。
让我们通过为两个非常基本的(但无用的)类 A 和 B 编写一个 __eq__来展示NotImplemented常量的使用。[对于这个简单的例子,为避免分心不实现__ne__()。但通常来说,除非有充分的理由,否则每次实现__eq__(),也应该实现__ne__()。]
# example.py
class A(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
if isinstance(other, A):
print('Comparing an A with an A')
return other.value == self.value
if isinstance(other, B):
print('Comparing an A with a B')
return other.value == self.value
print('Could not compare A with the other class')
return NotImplemented
class B(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
if isinstance(other, B):
print('Comparing a B with another B')
return other.value == self.value
print('Could not compare B with the other class')
return NotImplemented
现在在 interpreter 中:
>>> from example import A, B
>>> a1 = A(1)
>>> b1 = B(1)
现在我们可以尝试对__eq __() 的不同调用并查看会发生什么。提醒一下,在 Python 中,a == b实际上是调用 a.__eq__(b):
>>> a1 == a1
Comparing an A with an A
True
如预期的那样,a1 等于 a1(本身),A 类中的eq () 方法处理此操作。将 b1 与自身进行比较也会得出类似的结果:
>>> b1 == b1
Comparing a B with another B
True
如果我们现在比较 a1 和 b1,会怎么样?由于 A 的__eq __()会检查 other 参数是不是 B 的实例,我们期望 a1 .__ eq __(b1)处理比较操作并返回 True:
>>> a1 == b1
Comparing an A with a B
True
现在,如果我们将 b1 与 a1 进行比较(即调用 b1.__eq__(a1)),我们应该期望返回NotImplemented。这是因为 B 的__eq __()仅与其他 B 的实例进行比较。让我们看看发生了什么:
>>> b1 == a1
Could not compare B against the other class
Comparing an A with a B
True
b1 .__ eq __(a1)方法返回 NotImplemented导致 A 的__eq __()方法被调用,并且由于在 A 的__eq __()中定义了 A 和 B 之间的比较,我们得到了正确的结果(True)。
这就是返回 NotImplemented所做的事情。NotImplemented告诉运行时它应该请求 other 来满足操作。 在表达式b1 == a1中,b1 .__ eq __(a1)返回 NotImplemented,它告诉 Python 尝试调用 a1 .__ eq __(b1)。 由于 a1 足够知道返回 True,所以表达式可以成功。 如果 A 的__eq __()也返回NotImplemented,那么运行时将回退到基于对象标识(在 CPython 中是对象在内存中的地址)的相等内置行为。
注意,当b1 .__ eq __(a1)失败时抛出一个NotImpementedError异常会突破代码调用,除非被捕获,但 NotImplemented不会被抛出并可以用于进一步的测试。
扩展阅读:
- Python 3.7 将引入 dataclass 装饰器
- Flask 发布 1.0 稳定版
- 使用 Python 和 Click 编写命令行应用程序
- Python:range 对象并不是迭代器
- PyPI 终于支持 Markdown 了
极光日报,极光开发者旗下媒体。 每天导读三篇英文技术文章。
